home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung / Power-Programmierung (Tewi)(1994).iso / magazine / nan_news / toolkit / _whereis.asm next >
Assembly Source File  |  1991-08-15  |  24KB  |  535 lines

  1. ; File......: _WHEREIS.ASM
  2. ; Author....: Steve Larsen
  3. ; CIS ID....: 76370,1532
  4. ; Date......: $Date:   15 Aug 1991 23:08:08  $
  5. ; Revision..: $Revision:   1.1  $
  6. ; Log file..: $Logfile:   E:/nanfor/src/_whereis.asv  $
  7. ;
  8. ; This is an original work by K. Stephan Larsen and is placed in
  9. ; the public domain.
  10. ;
  11. ; Modification history:
  12. ; ---------------------
  13. ;
  14. ; $Log:   E:/nanfor/src/_whereis.asv  $
  15. ;  
  16. ;     Rev 1.1   15 Aug 1991 23:08:08   GLENN
  17. ;  Forest Belt proofread/edited/cleaned up doc
  18. ;  
  19. ;     Rev 1.0   07 Jun 1991 21:56:10   GLENN
  20. ;  Initial revision.
  21. ;
  22. ;
  23.  
  24. PUBLIC __ft_where, __ft_tree
  25.  
  26. EXTRN   __storc:far, __retni:far, __parinfo:far, __parclen:far
  27. EXTRN   __parc:far, __xfree:far, __xalloc:far
  28.  
  29. ;
  30. ; Create offsets to mvars and DTA buffering area.  The segment "DATASG"
  31. ;  is culled from the free pool, therefore goes away when these functions
  32. ;  are not active.  All mvar initialization must take place at
  33. ;  runtime, rather than compiletime.
  34. ;
  35. DATASG  SEGMENT  'DATA'
  36.  
  37. filename        db      13 dup(?), ?            ; passed filename
  38. olddrive        db      ?                       ; our current drive
  39. eop        dw    ?                       ; pointer to end-of-path string
  40. count           dw      ?                       ; current element
  41. is_array        dw      ?                       ; parm No., if array was passed
  42. a_count         db      ?                       ; array length
  43. dirname         db      4 dup(?)                ; '*.*' mask for directories
  44. dir_nest        db      ?                       ; directory level
  45. dta_ptr         db      ?                       ; pointer to current dir dta
  46. path            db      ?, 20 * 14 dup(?)       ; buffer for current path
  47. dta_buff        db      20 * 43 dup(?)          ; DTA for directories
  48. std_dta         db      128 DUP(?)              ; DTA for files
  49.  
  50. dta_file_offset equ     1Eh                     ; offset to filename within DTA
  51. dta_attr_offset equ     15h                     ; offset to file type within DTA
  52. dta_len         equ     43                      ; length of DTA that we're interested in
  53. segsize         equ     $ - filename            ; amount of free pool memory req'd
  54.  
  55. DATASG  ends
  56.  
  57. ; local vars go on stack, this is necessary since we cannot access data
  58. ;  within our data seg until it is allocated
  59.  
  60. oldsegloc       equ     <ss:[bp-02h]>           ; Clipper's DS
  61. newsegloc       equ     <ss:[bp-04h]>           ; our data area's Segment
  62. newoffset       equ     <ss:[bp-06h]>           ; our data area's Offset
  63. newsegment      equ     <ss:[bp-08h]>           ; after adjusting to the first
  64.                                                 ; paragraph within our data
  65.                                                 ; area, this is the "Segment"
  66.                                                 ; value of our data seg
  67.  
  68. _NANFOR segment word public 'CODE'
  69.         ASSUME CS:_NANFOR
  70.  
  71. __ft_where PROC    FAR
  72.         push    ds                      ; save Clipper's environment
  73.         push    es
  74.         push    di
  75.         push    si
  76.         push    bp
  77.         mov     bp, sp
  78.         sub     sp, 08h                 ; make room on stack for locals
  79.  
  80. w_1:    call    GetParms                ; fetch parms, set up our data seg
  81.         mov     ds, newsegloc           ; now point DS to our data seg
  82.         assume  ds:datasg
  83.         mov     ax, offset path         ; point to the current path (starts
  84.         inc     ax     
  85.         mov     eop, ax                 ; first EOP is 1 past "\"
  86.         call    HuntMDown               ; look for files in root directory
  87.  
  88. w_2:    call    FirstDir                ; find first subdirectory
  89.         jc      w_4                     ;  no subdir, set DTA back 1 dir lvl
  90.  
  91. w_3:    call    IsParent                ; found dir, check for DOS signature
  92.         jc      w_5                     ;  nope, go to next directory
  93.  
  94.         call    HuntMDown               ; OK, now look for files in directory
  95.  
  96. w_6:    call    UpDir                   ; move DTA up a level for subdirs
  97.         jmp     w_2                     ;  and do it all over again
  98.  
  99. w_4:    call    DownDir                 ; go back one level, look for another
  100. w_5:    call    NextDir                 ;   subdir. If CY returns set, no more
  101.         jc      w_4                     ;   subdirs, back up another level...
  102.         jmp     w_3                     ; subdir was found, continue
  103.  
  104. HuntMDown:                              ; requires EOP in BL, DTA set
  105.         call    FindFile                ;  set up to look for files
  106.                                         ;  DI points to EOP
  107.         call    FindFirst               ; find first matching file in dir
  108. h_1:    jc      h_3                     ; if not found, return to calling routine
  109.  
  110.         inc     count                   ; file was found, increment count
  111.  
  112.         mov     si, offset std_dta + dta_file_offset    ; and point SI to 
  113.                                         ; file's name within current DTA
  114.  
  115.         call    File2Path               ; add filename to end of current path
  116.         call    Save2Array              ; copy full path/filename to array
  117.  
  118. h_2:    call    FindNext                ; set up DOS to find next file/dir
  119.         jmp     h_1
  120.  
  121. h_3:    clc                             ; clear carry if set by parent dir
  122.         retn                            ; endp HuntMDown
  123.  
  124. FirstDir:                               ; locates first subdir in a level
  125.         call       FindDir              ; set up DOS search parms for a dir
  126.         call       MakePath             ; create the path
  127.         mov        si, offset dirname   ; add the "*.*" to the path
  128.         call       File2Path
  129.         mov        cx, 10h              ; directory attribute to search for
  130.         call       FindFirst            ; go do it
  131.         retn
  132.  
  133. IsParent:                               ; checks for "." or ".."
  134.     mov    ah, 2Fh                 ; fetch current DTA in ES:BX
  135.     int    21h
  136.         mov     si, bx                  ; point SI to DTA
  137.         add     si, dta_file_offset     ; point SI to dirname within DTA
  138.         lodsb                           ; fetch first char of dirname
  139.         clc
  140.         cmp     al, '.'                 ; check if parent directory
  141.         jne     ip_1                    ;  yep, this is a legit directory
  142.         stc                             ;  nope, set CY to inform calling
  143. ip_1:   retn                            ;  routine
  144.  
  145. NextDir:                                ; finds next subdir in current level
  146.         call    FindDir                 ; select directory DTA
  147.         mov     cx, 10h                 ; directory attribute to look for
  148.         call    FindNext                ; go a'lookin
  149.         retn
  150.  
  151. FindDir:                                ; sets DTA to current directory DTA
  152.         mov     dx, offset dta_buff     ; returns with carry set upon failure
  153.         xor     cx ,cx
  154.         mov     cl, dta_ptr             ; get current dir level, test for
  155.         cmp     cx, 0                   ;  bottom
  156.         je fd_1                         ; 
  157. fd_2:   add     dx, dta_len             ; if not, increment DX to proper level
  158.         loop    fd_2
  159. fd_1:   mov     ah, 1Ah                 ; set DTA
  160.         int     21h
  161.         retn
  162.  
  163. FindFile:                               ; sets DTA to file DTA
  164.         mov     dx, offset std_dta      ; point to file DTA
  165.         mov     ah, 1Ah
  166.         int     21h                     ; set it
  167.  
  168.         call    MakePath                ; construct current path
  169.         mov     si, offset filename     ; add the filespec
  170.         call    File2Path
  171.         xor     cx, cx                  ; set attribute for normal files
  172. ff_1:   retn
  173.  
  174. UpDir:
  175.         inc     dta_ptr                 ; inc the nest and segment pointers
  176.         inc     dir_nest
  177. retn
  178.  
  179. DownDir:                                ; clears last DTA for reuse
  180.         mov     di, offset dta_buff + dta_file_offset   ; point DI to last 
  181.         xor     cx, cx                  ; dirname searched by multiplying 
  182.         mov     cl, dta_ptr             ; length of DTA times No of DTA's 
  183.         cmp     cx, 0
  184.         je      mm_2                    ; if at root skip the multiply part
  185. mm_1:   add     di, dta_len             ; do the multiplication
  186.         loop    mm_1
  187.  
  188. mm_2:   mov     al, 0                   ; poke a null to clear any data here
  189.         stosb
  190.  
  191.         dec     dta_ptr                 ; dec the dir seg pointer and 
  192.         dec     dir_nest                ;  the nest level pointer
  193.  
  194.         jns     mm_3
  195.         jmp     Done                    ; ptr < 0 when finished in the root
  196. mm_3:   retn
  197.  
  198. FindFirst:                              ; finds first matching file/dir
  199.         push    es                      ; sets carry if no match found
  200.         push    bx                      ; current DTA and file attrib was
  201.         push    di                      ; set by calling routine
  202.         mov     ah, 2Fh                 ; get DTA in ES:BX for func 4Eh call
  203.         int     21h
  204.         mov     dx, offset path         ; point to filespec to search for
  205.         mov     ah, 4Eh                 ; find first matching file
  206.         int     21h
  207.         jc      fr_2                    ; carry set, no find
  208. fr_1:   call    IsMatch                 ; test if we stopped at a parent dir
  209.         jnc     fr_2                    ; nope, all's well so return
  210.         mov     ah, 4Fh                 ;  otherwise, find next dir
  211.         int     21h
  212.         jc      fr_2                    ; no more dirs, we've failed
  213.         jmp     fr_1
  214. fr_2:   pop    di
  215.         pop    bx
  216.         pop    es
  217.         retn
  218.  
  219. FindNext:                               ; looks for next occurance of file/dir
  220.         push    es                      ; last found in current DTA
  221.         push    bx                      ; sets CY if no matching file found
  222.         mov     ah, 2Fh                 ; fetch DTA in ES:BX
  223.         int     21h
  224.         mov     ah, 4Fh                 ; find next matching file
  225.         int     21h
  226.         jc      fn_2                    ; no find, return with CY set
  227. fn_1:   call    IsMatch                 ; found, test attribute
  228.         jnc      fn_2
  229.         mov     ah, 4Fh                 ; if no match, find next file
  230.         int     21h
  231.         jc      fn_2                    ; exit on no more files
  232.         jmp     fn_1
  233. fn_2:   pop    bx
  234.         pop    es
  235.         retn
  236.  
  237. IsMatch:clc                             ; sets carry if attr does not match
  238.         cmp     cl, 0                   ; if attribute is zero, skip test
  239.         je      im_1
  240.         test    cl, es:[bx + dta_attr_offset]      ; AND attribute with file's
  241.         jnz     im_1
  242.         stc                     ; AND unsuccessful, set carry for no match
  243. im_1:   retn
  244.  
  245. MakePath:                               ; builds path and exits with DI 
  246.         push    es                      ; pointing to EOP (0)
  247.         push    si
  248.         mov     di, offset path 
  249.         mov     dl, dta_ptr
  250.         mov     cx, offset dta_buff + dta_file_offset ; point to first dir.
  251. m_1:    mov     al, '\'
  252.         stosb
  253. m_2:    mov     si, cx                  ; point to directory name
  254.         lodsb
  255.         cmp     al, 0                   ; first character of dirname is null
  256.         je      m_4                     ;   if new segment
  257. m_3:    stosb
  258.         lodsb
  259.         cmp     al, 0                   ; end of directory name?
  260.         jne     m_3
  261.         mov     al, '\'                 ; yes, add trailing backslash
  262.         stosb
  263.         cmp     dl, 0                   ; check for last directory segment
  264.         je      m_4
  265.         add     cl, dta_len             ; point to next directory name
  266.         dec     dl                      ; decrement segment number
  267.         jmp     m_2                     ; do it again
  268. m_4:    mov     eop, di                 ; save end of path marker
  269.         mov     al, 0                   ; terminate path with a null
  270.         stosb
  271.         pop     si
  272.         pop     es                      ; point ES:SI to filename
  273.         retn
  274.  
  275. File2Path:                              ; appends file/dirname to end-of-path
  276.         mov     di, eop                 ; requires DS:SI pointing to filename
  277.         mov     cx, 14                  ; and ES:DI pointing to end-of-path
  278. rep     movsb
  279.         retn
  280.  
  281.  
  282. Done:                                   ; global return to Clipper routine
  283.         mov     cx, count               ; save return code for later
  284.         mov     ds, newsegloc           ; restore ourselves to original drive
  285.         mov     dl, olddrive
  286.         mov     ah, 0Eh
  287.         int     21h
  288.  
  289.         mov     ds, oldsegloc           ; point DS to Clipper's DS
  290.         mov     dx, newsegloc           ; return our dataseg to free pool
  291.         mov     ax, newoffset
  292.         push    dx
  293.         push    ax
  294.         call    __xfree
  295.  
  296.         mov     sp, bp                  ; skip SP back to beginning of 
  297.                                         ;  local vars. This method is
  298.                                         ;  necessary because we don't know
  299.                                         ;  how we got here, whether via a
  300.                                         ;  JMP or a CALL, so the stack could
  301.                                         ;  contain just about anything
  302.  
  303.         pop     bp                      ; restore Clipper's environment
  304.         pop     si
  305.         pop     di
  306.         pop     es
  307.         pop     ds
  308.  
  309.         push    cx                      ; send error code (or # hits) to Clippie
  310.     call    __retni
  311.     add    sp, 2
  312.         retf                            ; and we're outta here!
  313.  
  314. ;------------------------------------------------------------
  315. ;  GetParms    -  Local procedure to read in command line & set locals
  316. ;------------------------------------------------------------
  317. GetParms:
  318.  
  319.         mov     oldsegloc, ds           ; save Clipper's DS
  320.         call    MakeMem                 ; get some memory in free pool
  321.         mov     ds, newsegloc           ; point DS and ES to our dataseg
  322.         mov     es, newsegloc
  323.  
  324.         mov     word ptr count, 0       ; initialize variables
  325.         mov     byte ptr path, '\'      ; starting path is at the root
  326.         mov     byte ptr eop, offset path + 1 ; starting end-of-path
  327.         mov     byte ptr is_array, 0    ; default is no array passed
  328.         mov     word ptr dirname[0],     '.*'  ; dir pattern is *.*
  329.         mov     word ptr dirname[2],  0 + '*'
  330.         mov     word ptr filename[0],    '.*'  ; default filespec is *.*
  331.         mov     word ptr filename[2], 0 + '*'
  332.         mov     byte ptr dir_nest, 0    ; initial nesting level is 0 (duh)
  333.         mov     byte ptr dta_ptr,  0
  334.  
  335.         mov     cx, 10 * 43             ; fill DTA buffer areas with nulls
  336.         xor     ax, ax
  337.         cld
  338.         mov     di, offset dta_buff
  339. repne   stosw
  340.  
  341.         mov     ah, 19h                 ; fetch current drive and save
  342.         int     21h
  343.         mov     olddrive, al
  344.  
  345.         mov     ds, oldsegloc           ; restore Clipper's DS for PARxx funcs
  346.  
  347.     xor    ax,ax                ; fetch no. of parms passed
  348.     push    ax
  349.     call    __parinfo
  350.     add    sp,2
  351.  
  352.         or      ax, ax                  ; if no parms use defaults
  353.         jz      gp_Done
  354.  
  355.         push    ax                      ; save parm count
  356.         mov     ax, 1                   ; test first parm type
  357.         call    gp_array                ;   for array
  358.         cmp     byte ptr es:is_array, 0 ; is it an array?
  359.         ja      gp_done                 ;  yes, we're done (ignore remaining 
  360.                                         ;   parms)
  361.         push    ax                      
  362.         call    __parclen               ; get len of drive/filespec
  363.         mov     cx, ax                  ; put length in cx
  364.         pop     ax                      ; retrieve parm number
  365.         cmp     cx, 0                   ; test for no file/drive spec passed
  366.         je      gp_next                 ;  nothing there, get next parm
  367.         push    cx                      ; otherwise save length
  368.         push    ax                      ;  then parm no.
  369.         call    __parc                  ; fetch parm addr in DX:AX
  370.         add     sp, 2
  371.         pop     cx                      ; retrieve length in CX
  372.         mov     es, newsegloc           ; point ES:DI to filename
  373.         mov     di, offset filename
  374.         push    dx                      ; point DS:SI to passed parm
  375.         pop     ds
  376.         push    ax
  377.         pop     si
  378.         cmp     cx, 2                   ; if a only a single char was passed
  379.         jae     gp_isdrive              ;  assume it to be a filespec
  380.         movsb                           ;  filespec is now ?.*
  381.         jmp     gp_next                 ; go after next parm
  382.  
  383. gp_isdrive:                             ; test if passed parm contains a drivespec
  384.         push    cx                      ; save length
  385.         mov     al, [si+1]              ; look at 2nd char for colon
  386.         cmp     al, ":"
  387.         jne     gp_strcopy              ; nope, must just be a filespec
  388.         lodsw                           ; yep, fetch the drive letter
  389.         pop     cx                      ;  subtract drive + colon from length
  390.         sub     cx, 2
  391.         push    cx                      ; save revise length for later
  392.         and     al, 5Fh                 ; capitialize the drive letter
  393.         sub     al, 41h                 ; convert from char to numeric, A:=0
  394.  
  395.         mov     dx, ax                  ; test if this is a valid drive
  396.         mov     ah, 0Eh                 ;  by attempting to change to it
  397.         int     21h
  398.         cmp     al, dl                  ; check if spec'd drive is out of range
  399.         jae     gp_strcopy
  400.         jmp     Done                    ; no drive there, go back to Clippie
  401.  
  402. gp_strcopy:
  403.         pop     cx                      ; retrieve filespec len
  404.         or      cx, cx                  ; if len = 0, 
  405.         jz      gp_next                 ;  leave *.* as default search string
  406. repne   movsb                           ; otherwise save filespec
  407.         xor     al, al
  408.         stosb                           ; and add a null terminator
  409.  
  410. gp_next:
  411.         mov     ds, oldsegloc           ; restore Clipper's DS for PARxx funcs
  412.         pop     ax                      ; now check for second parm
  413.         cmp     ax, 2                   ; check if 2nd parm passed
  414.         jb      gp_done                 ;  no, we're done
  415.         mov     ax, 2                   ; otherwise, check second parm
  416.         call    gp_array                ; for arrayness, then we're done
  417. gp_Done:
  418.         retn
  419.  
  420. gp_array:
  421.         push    ax                      ; test parm for arrayness
  422.         call    __parinfo
  423.         mov     es, newsegloc           ; restore ES after __parinfo 
  424.         mov     bx, ax
  425.         pop     ax
  426.         test    bx, 512                 ; is it an array?
  427.         je      gpar1                   ;   if yes, save array's parm No.
  428.         mov     es:is_array, ax         ; is_array = 0 if no parm, else 1 or 2
  429. gpar1:  retn
  430.  
  431. MakeMem:                                ; creates a temp dataseg
  432.         mov     ax, segsize             ; get some memory
  433.         add     ax, 16                  ; account for paragraph boundary
  434.         push    ax
  435.         call    __xalloc                ; request some space
  436.         add     sp, 2
  437.         mov     newoffset, ax           ; save address for later release
  438.         mov     newsegment,dx           ;  upon return to Clipper
  439.         or      dx, ax                  ; oh yeah, check if we even got some
  440.         jnz     gpmm_1                  ;  memory, if not, time to bomb by
  441.         jmp     Done                    ;  jumping directly to exit routine
  442.  
  443. gpmm_1: mov     dx, newsegment          ; restore mem segment to DX
  444.         add     ax, 15                  ; force ax to next page boundary
  445.         shr     ax, 1                   ; drop low byte (ax/16)
  446.         shr     ax, 1
  447.         shr     ax, 1
  448.         shr     ax, 1
  449.         add     dx, ax                  ; convert to an even segment boundary
  450.         mov     newsegloc, dx           ;   and save. We now our own dataseg
  451.         retn                            ;   from the free pool 
  452.  
  453. Save2Array:
  454.         cmp     word ptr is_array, 0    ; don't attempt to save if no array
  455.         je      sta1
  456.         push    es                      ; __STORC destroys ES so save it
  457.         push    word ptr count          ; array ordinal number
  458.         push    word ptr is_array       ; parm number
  459.         push    ds                      ; segment of string
  460.         mov     ax, offset path         ; offset of string
  461.         push    ax
  462.         mov     ds, oldsegloc           ; restore Clippie's DS befo the call
  463.         call    __storc                 ; save to the array
  464.         add     sp, 8
  465.         pop     es                      ; get back our ES
  466.         mov     ds, newsegloc           ; restore DS to our area
  467.         or      ax, ax                  ; error if AX is 0
  468.         jnz     sta1
  469.         mov     is_array, ax            ; if error disable further attempts
  470. sta1:   retn
  471.  
  472. __ft_where endp
  473.  
  474. __ft_tree proc    far
  475.         push    ds                      ; save Clipper's environment
  476.         push    es
  477.         push    di
  478.         push    si
  479.         push    bp
  480.         mov     bp, sp
  481.         sub     sp, 08h
  482.  
  483. t_1:    call    GetParms                ; init vars and setup our dataseg
  484.         mov     ds, newsegloc
  485.         assume  ds:datasg
  486.         call    FirstDir                ; try to find anything in root
  487.         jc      t_1a                    ; no files, find out why
  488.         call    save_root               ; found something, root exists
  489.         mov     di, offset dta_buff + dta_file_offset   ; clear name of found file
  490.         xor     al, al
  491.         stosb
  492.         jmp     t_2
  493.  
  494. t_1a:   cmp     al, 12h                 ; test for no more files
  495.         jne     t_1b
  496.         call    save_root               ; no files, save root then exit
  497.         mov     count, 1
  498. t_1b:   jmp     Done
  499.  
  500. t_2:    call    FirstDir                ; find first subdirectory
  501.         jc      t_4                     ; no subdir, set DTA back one directory area
  502.  
  503. t_3:    call    IsParent                ; check for DOS signature
  504.         jc      t_5
  505.  
  506.         mov     ax, count               ; got one, increment count
  507.         inc     ax
  508.         mov     count, ax
  509.  
  510.         call    MakePath
  511.  
  512.         call    Save2Array              ; do the save
  513.  
  514. t_6:    call    UpDir                   ; move DTA up a level for subdirs
  515.         jmp     t_2
  516.  
  517. t_4:    call    DownDir                 ; go back one level
  518. t_5:    call    NextDir                 ; if CY bad path, look again
  519.         jc      t_4                     ; if not found, go back again
  520.         jmp     t_3                     ; if found, continue
  521.  
  522. save_root:
  523.         mov     ax, 1                   ; no files, insert the root then quit
  524.         mov     count, ax
  525.         mov     di, eop                 ; put null terminator after last \
  526.         xor     al, al
  527.         stosb
  528.         call    Save2Array              ; save the root
  529.         retn
  530. __ft_tree endp
  531.  
  532. _NANFOR ends
  533.         end
  534. 
  535.